﻿using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Drawing.Drawing2D;
using System.Linq;
using System.Text;
using System.Windows.Forms;
using System.IO;
using Spike_EBC_Designer.ViewModel;

namespace Spike_EBC_Designer
{
    public partial class Form1 : Form
    {
        private Grid _grid;
        private Dictionary<Relation, GraphicsPath> _relationsDrawn;


        public Form1()
        {
            InitializeComponent();
        }


        private void Form1_Load(object sender, EventArgs e)
        {
            CreateNewModel();
            try
            {
                _grid = FilesystemAdapter.Load("default.ebc");
            }
            catch{}
            Display();
        }


        private void Form1_FormClosing(object sender, FormClosingEventArgs e)
        {
            FilesystemAdapter.Store("default.ebc", _grid);
        }


        private void toolStripMenuItem3_Click(object sender, EventArgs e)
        {
            CreateNewModel();
        }

        private void CreateNewModel()
        {
            openFileDialog1.FileName = "";
            saveEbcFileDialog1.FileName = "";
            _grid = new Grid(10, 10);
            _grid.Label = "Mainboard";
            Display();
        }

        private void ladenToolStripMenuItem_Click(object sender, EventArgs e)
        {
            if (openFileDialog1.ShowDialog() == System.Windows.Forms.DialogResult.OK)
            {
                _grid = FilesystemAdapter.Load(openFileDialog1.FileName);
                saveEbcFileDialog1.FileName = Path.GetFileName(openFileDialog1.FileName);
                Display();
            }
        }

        private void speichernUnterToolStripMenuItem_Click(object sender, EventArgs e)
        {
            if (saveEbcFileDialog1.ShowDialog() == System.Windows.Forms.DialogResult.OK)
                FilesystemAdapter.Store(saveEbcFileDialog1.FileName, _grid);
        }


        private void exportNachEbcxmlToolStripMenuItem_Click(object sender, EventArgs e)
        {
            if (saveEbcXmlFileDialog1.ShowDialog() == System.Windows.Forms.DialogResult.OK)
                EbcXmlExportAdapter.Export(saveEbcXmlFileDialog1.FileName, _grid);
        }


        private void beendenToolStripMenuItem_Click(object sender, EventArgs e)
        {
            this.Close();
        }


        private void Display()
        {
            _grid.Resize(pictureBox1.Width, pictureBox1.Height);

            var canvas = new Bitmap(_grid.Width, _grid.Height);
            using (var gc = Graphics.FromImage(canvas))
            {
                // Hintergrund einfärben
                gc.FillRectangle(Brushes.White, 0, 0, canvas.Width, canvas.Height);

                using (var gridFont = new Font("Verdana", 20))
                {
                    gc.DrawString(_grid.Label, gridFont, Brushes.LightGray, 15, 15);
                }

                // grid zeichnen
                for (var i = 1; i < _grid.ColCount; i++)
                    gc.DrawLine(Pens.LightGray, _grid[i,0].X, 0, _grid[i,0].X, _grid[0,_grid.RowCount-1].Y+_grid[0,_grid.RowCount-1].Height);

                for (var i = 1; i < _grid.RowCount; i++)
                    gc.DrawLine(Pens.LightGray, 0, _grid[0, i].Y, _grid[_grid.ColCount - 1, 0].X + _grid[_grid.ColCount - 1, 0].Width, _grid[0, i].Y);

                // expando zellen zeichnen
                for (var i = 0; i < _grid.ColCount; i++)
                    gc.FillRectangle(Brushes.DarkGray, _grid.ColInserters[i].X, _grid.ColInserters[i].Y, _grid.ColInserters[i].Width, _grid.ColInserters[i].Height);

                for (var i = 0; i < _grid.RowCount; i++)
                    gc.FillRectangle(Brushes.DarkGray, _grid.RowInserters[i].X, _grid.RowInserters[i].Y, _grid.RowInserters[i].Width, _grid.RowInserters[i].Height);

                // funktionseinheiten zeichnen
                using (var font = new Font("Verdana", 9))
                {
                    for (var col = 0; col < _grid.ColCount; col++)
                        for (var row = 0; row < _grid.RowCount; row++)
                        {
                            var cell = _grid[col, row];
                            if (!cell.IsEmpty)
                            {
                                var cellColor = Brushes.Blue;
                                if (cell.IsSelected)
                                    cellColor = Brushes.DarkBlue;

                                if (cell.Label == "this")
                                    gc.FillEllipse(cellColor, cell.X, cell.Y, cell.Width, cell.Height);
                                else
                                    gc.FillRectangle(cellColor, cell.X, cell.Y, cell.Width, cell.Height);

                                gc.DrawString(cell.Label, font, Brushes.White, cell.X+cell.Width/2-gc.MeasureString(cell.Label, font).Width/2, cell.Y);
                            }
                        }
                }


                //// wires zeichnen
                using (var wirePenNormal = new Pen(Color.Red, 2))
                using (var wirePenSelected = new Pen(Color.DarkRed, 2))
                using(var font = new Font("Verdana", 7))
                {
                    var arrowTip = new AdjustableArrowCap(5, 5);
                    wirePenNormal.CustomEndCap = arrowTip;
                    wirePenSelected.CustomEndCap = arrowTip;


                    _relationsDrawn = new Dictionary<Relation, GraphicsPath>();
                    foreach(var rel in _grid.Relations)
                    {
                        var relPen = wirePenNormal;
                        if (rel.IsSelected) relPen = wirePenSelected;
                        //gc.DrawLine(relPen, rel.X, rel.Y, rel.X + rel.Width, rel.Y + rel.Height);

                        var gp = new GraphicsPath();
                        gp.AddCurve(new[] {new Point(rel.X, rel.Y), 
                                           new Point(rel.X + 7 + rel.Width/2, rel.Y + 7 + rel.Height/2),
                                           new Point(rel.X + rel.Width, rel.Y + rel.Height)});
                        gc.DrawPath(relPen, gp);
                        _relationsDrawn.Add(rel, gp);

                        gc.DrawString(rel.OutputPinName, font, Brushes.DarkGray, rel.X+rel.Width*0.2f, rel.Y+rel.Height*0.2f);
                        gc.DrawString(rel.InputPinName, font, Brushes.DarkGray, rel.X+rel.Width*0.8f, rel.Y+rel.Height*0.8f);
                        gc.DrawString(rel.Typename, font, Brushes.DarkGray, rel.X + rel.Width / 2, rel.Y + rel.Height / 2);
                    }
                }

                pictureBox1.Image = canvas;
            }
        }


        private void Form1_Resize(object sender, EventArgs e)
        {
            Display();
        }


        private void pictureBox1_DoubleClick(object sender, EventArgs e)
        {
            var em = e as MouseEventArgs;
            var melem = _grid.Find(em.X, em.Y);

            var cell = melem as Cell;
            if (cell != null && cell.IsEmpty)
            {
                cell.Label = "name";
                _grid.Select(cell);
                propertyGrid1.SelectedObject = new CellProperties { Label = cell.Label };
            }

            var ins = melem as Inserter;
            if (ins != null)
                ins.Execute();

            Display();
        }


        private void pictureBox1_Click(object sender, EventArgs e)
        {
            var em = e as MouseEventArgs;

            object melem = null;

            using (var p = new Pen(Brushes.Black, 7))
            {
                foreach (var wire in _relationsDrawn)
                {
                    if (wire.Value.IsOutlineVisible(em.X, em.Y, p))
                    {
                        melem = wire.Key;
                        break;
                    }
                }
            }


            if (melem == null) melem = _grid.Find(em.X, em.Y);


            var cell = melem as Cell;
            if (cell != null)
            {
                if (ModifierKeys != Keys.Shift)
                {
                    // select cell
                    if (cell.IsEmpty)
                        propertyGrid1.SelectedObject = null;
                    else
                    {
                        _grid.Select(cell);
                        propertyGrid1.SelectedObject = new CellProperties { Label = cell.Label };
                    }
                }
                else if (_grid.Selected != null)
                {
                    // add wire between cells
                    var outputCell = _grid.Selected as Cell;
                    if (!cell.IsEmpty && cell != outputCell)
                    {
                        _grid.AddRelation(outputCell, cell);

                        outputCell.IsSelected = false;
                        propertyGrid1.SelectedObject = null;
                    }
                }
            }
            else
                _grid.Select(null);



            var rel = melem as Relation;
            if (rel != null)
            {
                _grid.Select(rel);
                propertyGrid1.SelectedObject = new RelationProperties { Typename = rel.Typename, OutputPinName=rel.OutputPinName, InputPinName=rel.InputPinName};
            }


            if (propertyGrid1.SelectedObject == null)
                propertyGrid1.SelectedObject = new GridProperties {Label = _grid.Label, Implements = _grid.Implements, Usings = _grid.Usings};


            Display();
        }


        private void propertyGrid1_PropertyValueChanged(object s, PropertyValueChangedEventArgs e)
        {
            if (propertyGrid1.SelectedObject as GridProperties != null)
                (propertyGrid1.SelectedObject as PropertyBag).Apply(_grid);
            else
                (propertyGrid1.SelectedObject as PropertyBag).Apply(_grid.Selected);
            Display();
        }
    }
}
